// This file is part of OpenMeca, an easy software to do mechanical simulation.
//
// Author(s)    :  - Damien ANDRE  <openmeca@gmail.com>
//
// Copyright (C) 2012 Damien ANDRE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "OpenMeca/Item/Body.hpp"
#include "OpenMeca/Item/Part.hpp"
#include "OpenMeca/Item/PartUser.hpp"
#include "OpenMeca/Item/PartUserPoint.hpp"
#include "OpenMeca/Core/UserItemCommonProperty.hpp"
#include "OpenMeca/Core/UserRootItemCommonProperty.hpp"
#include "OpenMeca/Gui/MainWindow.hpp"

#include "boost/serialization/export.hpp"
//Don't forget to export for dynamic serialization of child class
BOOST_CLASS_EXPORT(OpenMeca::Item::Body)

namespace OpenMeca
{  
  namespace Item
  {


    const std::string 
    Body::GetStrType()
    {
      return "Body";
    }

    void
    Body::Init()
    {
      Core::Singleton< Core::UserRootItemCommonProperty<Body> >::Get().CreateAction_All();
    }
     
  

      
    Body::Body()
      :Core::UserRootItem(Body::GetStrType(), Core::Singleton< Core::UserRootItemCommonProperty<Body> >::Get().GetRootTreeWidgetItem()),
       color_(),
       mass_(0.),
       massCenter_(0., 0., 0.), 
       quaternion_(0., 0., 0., 1.),
       frame_(massCenter_, quaternion_),
       inertia_(),
       fixed_(false)
    {
    }

    Body::~Body()
    {
    }

    const double&
    Body::GetMass() const
    {
      return mass_;
    }

    double&
    Body::GetMass()
    {
      return mass_;
    }


    const Geom::Matrix<_3D>& 
    Body::GetInertia() const
    {
      return inertia_;
    }

    Geom::Matrix<_3D>& 
    Body::GetInertia()
    {
      return inertia_;
    }



    const Geom::Point<_3D>& 
    Body::GetMassCenter() const
    {
      return massCenter_;
    }


    Geom::Point<_3D>& 
    Body::GetMassCenter()
    {
      return massCenter_;
    }


    const Geom::Quaternion<_3D>& 
    Body::GetQuaternion() const
    {
      return quaternion_;
    }

    Geom::Quaternion<_3D>& 
    Body::GetQuaternion()
    {
      return quaternion_;
    }

    const Geom::Frame<_3D>& 
    Body::GetFrame() const
    {
      return frame_;
    }
    
    Geom::Frame<_3D>& 
    Body::GetFrame()
    {
      return frame_;
    }


    const Util::Color& 
    Body::GetColor() const
    {
      return color_;
    }

    
    Util::Color& 
    Body::GetColor()
    {
      return color_;
    }


    const OpenMeca::Item::Body& 
    Body::GetBody() const
    {
      return *this;
    }

    OpenMeca::Item::Body& 
    Body::GetBody()
    {
      return *this;
    }
    

    const bool& 
    Body::IsFixed() const
    {
      return fixed_;
    }

    bool& 
    Body::IsFixed()
    {
      return fixed_;
    }

    void 
    Body::ToggleFix()
    {
      fixed_ = !fixed_;
    }

    void 
    Body::UpdateIcon()
    {
      Body::DrawIcon(GetIcon(), color_.GetQColor(), fixed_);
    }

    Core::SetOfBase<Part> 
    Body::GetParts()
    {
      Core::SetOfBase<Part> set;
      Core::SetOfBase<Part>::it it;
      Core::SetOf<Part>& partSet = Core::AutoRegister<Part>::GetGlobalSet();
      for (it=partSet.Begin() ; it != partSet.End(); it++ )
	{
	  if (&(*it)->GetBody() == this)
	    set.AddItem(**it);
	}
      return set;
    }

    Core::SetOfBase<Core::UserItem> 
    Body::GetAssociatedSelectedItem()
    {
      Core::SetOfBase<Core::UserItem> itemSet;
      Core::SetOfBase<Part> partSet = GetParts();
      Core::SetOf<Part>::it it;
      for (it=partSet.Begin() ; it != partSet.End(); it++ )
	itemSet.AddItem(**it);

      return itemSet;
    }


    void 
    Body::DrawIcon(QIcon& icon, QColor color, bool fixed)
    {
       //3D ball effect
      const int size = Gui::MainWindow::Get().GetIconSize();
      const int margin = 2;
      QPixmap pixmap(QSize(size,size));
      pixmap.fill(QColor (0, 0, 0, 0));
      QPainter painter(&pixmap);

      const int middle = size/2;

      QRadialGradient gradient(middle, middle, middle, middle, middle);
      gradient.setColorAt(0, Qt::white);
      gradient.setColorAt(1, color);
      QBrush brush(gradient);

      painter.setBrush(brush);
      painter.setPen(Qt::black);

      if (fixed)
	{
	  for (int i =2; i <  size; i=i+2)
	     painter.drawLine (0, i,  i, 0);
	}

      painter.setBrush(brush);
      painter.setPen(Qt::black);
      painter.drawEllipse(margin, margin, size-2*margin, size-2*margin);
      icon =  QIcon(pixmap);
    }


  }

}


namespace OpenMeca
{  
  namespace Core
  {

    QString
    Action_FixBody::Text()
    {
      return QString(QObject::tr("Fix/Unfix"));
    }

    QIcon
    Action_FixBody::Icon()
    {
      QIcon icon;
      OpenMeca::Item::Body::DrawIcon(icon, Qt::gray, true);
      return icon;
    }

    void
    Action_FixBody::DoAction(OpenMeca::Item::Body& body, Action& action)
    {
      std::cout << "Fix body" << std::endl;
      body.ToggleFix();
      System::Get().Update();
      System::Get().GetHistoric().SystemEdited();
      Gui::MainWindow::Get().AddToHistoric(action);
    }

    
    template<>
    void 
    UserItemCommonProperty<OpenMeca::Item::Body>::CreateAction_Specialized() 
    {
      Action& fixAction = *new ActionWithUserItemSelectionInterface<OpenMeca::Item::Body, Action_FixBody >();
      CommonProperty::AddAction(fixAction);
      CommonProperty::AddPopUpAction(fixAction);
      CreateAction_NewWithSelection<OpenMeca::Item::PartUserPoint>();
    }


    
    template<>
    void
    ItemCommonProperty<OpenMeca::Item::Body>::BuildIconSymbol()
    {
      QIcon icon;
      OpenMeca::Item::Body::DrawIcon(iconSymbol_, Qt::gray, false);
    }



  }
}
